/*
ID: icerupt1
PROG: milk6
LANG: C++11
*/

/* solution
 *
 * great problem. 输出字典序最小的最小割。
 * 网络流的题, 很裸，难点在输出字典序最小的割集方案。
 * 知道一个不错的方法，，没写。
 * 暴力的方法就是枚举所有可能为最小割的边（之前为了求边数将容量都设成了1），
 * 将容量设置成零在跑一遍最大流，如果最大流减少1，那么该边就是在割集当中。
 * 只要按字典序枚举就可以得到字典序最小的方案。
 *
 * 非暴力解法：
 * http://poj.org/showmessage?message_id=136776
 *
*/
#include <fstream>
#include <iostream>
#include <vector>
#include <limits>
#include <queue>

std::ifstream fin {"milk6.in" };
std::ofstream fout{"milk6.out"};

template <class T>
struct dinic
{
	using value_type = T;
	using size_type = int;

	struct edge {
		size_type from, to;
		value_type capacity, flow;
	};

	dinic(size_type num) : size(num)
	{
		graph.resize(num);	//[0, num)
		dist.resize(num);	//[0, num)
	}

	void add_edge(int u, int v, value_type cap)
	{
		edge tmp;
		tmp.from = u; tmp.to = v; tmp.capacity = cap; tmp.flow = 0;
		edges.push_back(tmp);
		graph[u].push_back(edges.size() - 1);

		tmp.from = v; tmp.to = u; tmp.capacity = 0; tmp.flow = 0;
		edges.push_back(tmp);
		graph[v].push_back(edges.size() - 1);
	}

	auto bfs_label(size_type source, size_type target)
	{
		std::fill(dist.begin(), dist.end(), -1);
		std::queue<size_type> q;
		q.push(source);
		dist[source] = 0;
		while (!q.empty()) {
			auto now = q.front();
			q.pop();
			for (auto it = graph[now].begin(); it != graph[now].end(); ++it) {
				edge e = edges[*it];
				if (dist[e.to] == -1 && e.capacity > e.flow) {
					q.push(e.to);
					dist[e.to] = dist[now] + 1;
				}
			}
		}
		return dist[target] != -1;
	}

	auto dfs(size_type v, size_type target, value_type f)
	{
		if (v == target || !f) return f;
		value_type block_flow = 0;
		for (auto it = graph[v].begin(); it != graph[v].end(); ++it) {
			edge & e = edges[*it];
			if (e.capacity > e.flow && dist[e.to] == dist[v] + 1) {
				value_type tmp = dfs(e.to, target,
						std::min(e.capacity - e.flow, f - block_flow));
				block_flow += tmp;
				e.flow += tmp;
				edges[(*it) ^ 1].flow -= tmp;
			}
		}
		if (!block_flow) dist[v] = -1;
		return block_flow;
	}

	auto max_flow(size_type source, size_type target)
	{
		value_type flow = 0;
		for (int tmp; bfs_label(source, target); )
			while ((tmp = dfs(source, target, capacity_inf))) flow += tmp;
		return flow;
	}

//private:
	value_type const capacity_inf = std::numeric_limits<value_type>::max();
	size_type size;
	std::vector<int> dist;
	std::vector<edge> edges;
	std::vector<std::vector<size_type>> graph;
};

int main()
{
	int n, m;
	fin >> n >> m;
	dinic<int> d(n);
	for (int i = 0, x, y, c; i < m; i++) {
		fin >> x >> y >> c;
		x--; y--;
		d.add_edge(x, y, c);
	}

	int max_flow = d.max_flow(0, n-1);
	std::cout << max_flow << ' ';
	fout << max_flow << ' ';

	for (auto i = 0; i < (int)d.edges.size(); i += 2) {
		if (d.edges[i].capacity == d.edges[i].flow)
			d.edges[i].capacity = 1;
		else
			d.edges[i].capacity = d.capacity_inf;
		d.edges[i].flow = 0;
		d.edges[i ^ 1].flow = 0;
	}
	max_flow = d.max_flow(0, n-1);
	std::cout << max_flow << '\n';
	fout << max_flow << '\n';

	for (auto i = 0; i < (int)d.edges.size(); i += 2) {
		if (d.edges[i].flow != d.edges[i].capacity) continue;
		int tmpc = d.edges[i].capacity;
		d.edges[i].capacity = 0;
		for (auto & j : d.edges) j.flow = 0;
		if (d.max_flow(0, n-1) == max_flow - 1) {
			//std::cout << (i/2) + 1 << ' ' << d.edges[i].from << ' ' << d.edges[i].to << ' '
			//			<< tmpc << '\n';
			std::cout << (i/2) + 1 << '\n';
			fout << (i/2) + 1 << '\n';
			tmpc = 0;
			max_flow--;
		}
		d.edges[i].capacity = tmpc;
		if (!max_flow) break;
	}
}

